#include "m3dLoader.h"
#include <fstream>

void CM3dLoaer::LoadM3d(const std::string& filename, 
	std::vector<PosVertex>& vertices,
	std::vector<UINT>& indices, 
	std::vector<Subset>& subsets, 
	std::vector<M3dMaterial>& materials,
	SkinnedData& skinnedData)
{
	std::ifstream infile(filename);
	
	std::string ignore;
	UINT numMaterials = 0;
	UINT numVertices, numTriangles;
	UINT numBones, numAnimationClips;

	if (infile)
	{
		getline(infile, ignore, '\n');
		infile >> ignore >> numMaterials;
		infile >> ignore >> numVertices;
		infile >> ignore >> numTriangles;
		infile >> ignore >> numBones;
		infile >> ignore >> numAnimationClips;

		ReadMaterials(infile, numMaterials, materials);
		ReadSubsets(infile, numMaterials, subsets);
		ReadVertices(infile, numVertices, vertices);
		ReadIndices(infile, numTriangles, indices);

		std::vector<XMFLOAT4X4> boneOffsets;
		std::vector<int> boneHierachy;
		std::map<std::string, AnimationClip> animations;
		ReadOffsets(infile, numBones, boneOffsets);
		ReadHierachy(infile, numBones, boneHierachy);
		ReadAnimationClips(infile, numBones, numAnimationClips, animations);

		skinnedData.Set(boneHierachy, boneOffsets, animations);
	}
}

void CM3dLoaer::ReadMaterials(std::ifstream& infile, UINT numMaterials, std::vector<M3dMaterial>& materials)
{
	std::string ignore;
	std::string diffuseMapName, normalMapName;
	float tmp;
	materials.resize(numMaterials);

	infile >> ignore;
	for (UINT i = 0; i < numMaterials; ++i)
	{
		infile >> ignore >> materials[i].Mat.Ambient.x >> materials[i].Mat.Ambient.y >> materials[i].Mat.Ambient.z;
		infile >> ignore >> materials[i].Mat.Diffuse.x >> materials[i].Mat.Diffuse.y >> materials[i].Mat.Diffuse.z;
		infile >> ignore >> materials[i].Mat.Specular.x >> materials[i].Mat.Specular.y >> materials[i].Mat.Specular.z;
		infile >> ignore >> materials[i].Mat.Specular.w;
		infile >> ignore >> tmp >> tmp >> tmp;
		infile >> ignore >> materials[i].AlphaClip;
		infile >> ignore >> ignore;
		infile >> ignore >> diffuseMapName;
		infile >> ignore >> normalMapName;

		materials[i].Mat.Ambient.w = 1.0f;
		materials[i].Mat.Diffuse.w = 1.0f;

		materials[i].DiffuseMapName.resize(diffuseMapName.size());
		materials[i].NormalMapName.resize(normalMapName.size());
		//convert to wstring
		copy(diffuseMapName.begin(), diffuseMapName.end(),
			materials[i].DiffuseMapName.begin());
		copy(normalMapName.begin(), normalMapName.end(),
			materials[i].NormalMapName.begin());
	}
}


void CM3dLoaer::ReadSubsets(std::ifstream& infile, UINT numSubsets, std::vector<Subset>& subsets)
{
	std::string ignore;
	subsets.resize(numSubsets);

	infile >> ignore;
	for (UINT i = 0; i < numSubsets; ++i)
	{
		infile >> ignore >> subsets[i].Id;
		infile >> ignore >> subsets[i].vertexStart;
		infile >> ignore >> subsets[i].VertexCount;
		infile >> ignore >> subsets[i].FaceStart;
		infile >> ignore >> subsets[i].FaceCount;
	}
}
void CM3dLoaer::ReadVertices(std::ifstream& infile, UINT numVertex, std::vector<PosVertex>& vertices)
{
	std::string ignore;
	float tmp;
	vertices.resize(numVertex);

	infile >> ignore;
	for (UINT i = 0; i < numVertex; ++i)
	{
		int boneIndices[4];
		infile >> ignore >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
		infile >> ignore >> vertices[i].Tangent.x >> vertices[i].Tangent.y >> vertices[i].Tangent.z >> tmp;
		infile >> ignore >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
		infile >> ignore >> vertices[i].TexCoord.x >> vertices[i].TexCoord.y;
		infile >> ignore >> vertices[i].Weights.x >> vertices[i].Weights.y >> vertices[i].Weights.z >> ignore;
		infile >> ignore >> boneIndices[0] >> boneIndices[1] >> boneIndices[2] >> boneIndices[3];
		vertices[i].BoneIndices[0] = (byte)boneIndices[0];
		vertices[i].BoneIndices[1] = (byte)boneIndices[1];
		vertices[i].BoneIndices[2] = (byte)boneIndices[2];
		vertices[i].BoneIndices[3] = (byte)boneIndices[3];
	}
}

void CM3dLoaer::ReadIndices(std::ifstream& infile, UINT numTriangle, std::vector<UINT>& indices)
{
	std::string ignore;
	indices.resize(numTriangle * 3);

	infile >> ignore;
	for (UINT i = 0; i < numTriangle; ++i)
	{
		infile >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
	}
}

void CM3dLoaer::ReadOffsets(std::ifstream& infile, UINT numBones, std::vector<XMFLOAT4X4>& boneOffsets)
{
	std::string ignore;
	boneOffsets.resize(numBones);

	infile >> ignore;
	for (UINT i = 0; i < numBones; i++)
	{
		infile >> ignore >> 
			boneOffsets[i](0, 0) >> boneOffsets[i](0, 1) >> boneOffsets[i](0, 2) >> boneOffsets[i](0, 3) >>
			boneOffsets[i](1, 0) >> boneOffsets[i](1, 1) >> boneOffsets[i](1, 2) >> boneOffsets[i](1, 3) >>
			boneOffsets[i](2, 0) >> boneOffsets[i](2, 1) >> boneOffsets[i](2, 2) >> boneOffsets[i](2, 3) >>
			boneOffsets[i](3, 0) >> boneOffsets[i](3, 1) >> boneOffsets[i](3, 2) >> boneOffsets[i](3, 3);
	}
}

void CM3dLoaer::ReadHierachy(std::ifstream& infile, UINT numBones, std::vector<int>& boneHierachy)
{
	std::string ignore;
	boneHierachy.resize(numBones);

	infile >> ignore;
	for (size_t i = 0; i < numBones; i++)
	{
		infile >> ignore >> boneHierachy[i];
	}
}

void CM3dLoaer::ReadAnimationClips(std::ifstream& infile, UINT numBones, UINT numClips, std::map<std::string, AnimationClip>& animations)
{
	std::string ignore;

	infile >> ignore;//header
	for (size_t i = 0; i < numClips; i++)
	{
		std::string clipName;
		infile >> ignore >> clipName;//animationclip name
		infile >> ignore; //{

		AnimationClip clip;
		clip.BoneAnimations.resize(numBones);

		for (size_t i = 0; i < numBones; ++i)
		{
			UINT keyframes;
			infile >> ignore >> ignore >> keyframes;//bonei #keyframes: n

			ReadBoneFrames(infile, keyframes, clip.BoneAnimations[i]);

		}
		infile >> ignore; //}

		animations[clipName] = clip;
	}

}

void CM3dLoaer::ReadBoneFrames(std::ifstream& infile, UINT numKeyframes, BoneAnimation& boneAnimation)
{
	std::string ignore;
	boneAnimation.Keyframes.resize(numKeyframes);

	infile >> ignore; //{
	for (size_t i = 0; i < numKeyframes; ++i)
	{
		float t = 0.0f;
		XMFLOAT3 p(0.0f, 0.0f, 0.0f);
		XMFLOAT3 s(1.0f, 1.0f, 1.0f);
		XMFLOAT4 q(0.0f, 0.0f, 0.0f, 1.0f);
		infile >> ignore >> t;
		infile >> ignore >> p.x >> p.y >> p.z;
		infile >> ignore >> s.x >> s.y >> s.z;
		infile >> ignore >> q.x >> q.y >> q.z >> q.w;

		boneAnimation.Keyframes[i].TimePos = t;
		boneAnimation.Keyframes[i].Translation = p;
		boneAnimation.Keyframes[i].Scale = s;
		boneAnimation.Keyframes[i].RotationQuat = q;
	}
	infile >> ignore; //}
}